package simpleGui;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.media.opengl.GL2;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.glu.GLU;

import processing.core.PApplet;
import processing.opengl.PGL;
import processing.opengl.PGraphicsOpenGL;

public class DirectOpenglCanvas implements MouseListener,MouseMotionListener {
	PApplet parent;
	// OpenGL
		GLU glu;
		FloatBuffer vbuffer;
		FloatBuffer cbuffer;
		FloatBuffer nbuffer;
		float[] projMatrix;
		float[] mvMatrix;
		int numPoints = 100000;
		
		DirectOpenglCanvas(PApplet parent){
			parent=parent;
			parent.addMouseListener(this);
			parent.addMouseMotionListener(this);
		}
		
		public void writeQuads(float[] xc,float[] yc,float[] zc,float[] xn,float[] yn,float[] zn,int[] quads) {
			parent.smooth();
			numPoints =quads.length;

			PGraphicsOpenGL pg = ((PGraphicsOpenGL) parent.g);
			PGL pgl = pg.beginPGL();
			GL2 gl2 = pgl.gl.getGL2();
			glu = pgl.glu;

			int vSize = (numPoints * 3);
			int cSize = (numPoints * 3);
			int nSize = (numPoints * 3);

			vSize = vSize << 2;
			cSize = cSize << 2;
			nSize = nSize << 2;

			vbuffer = ByteBuffer.allocateDirect(vSize)
					.order(ByteOrder.nativeOrder()).asFloatBuffer();
			cbuffer = ByteBuffer.allocateDirect(cSize)
					.order(ByteOrder.nativeOrder()).asFloatBuffer();
			nbuffer = ByteBuffer.allocateDirect(cSize)
					.order(ByteOrder.nativeOrder()).asFloatBuffer();

			for (int i = 0; i < quads.length; i += 4) {
				for (int d = 0; d < 4; d++) {
					int index = quads[i + d];
					vbuffer.put(xc[index] * 20);
					vbuffer.put(yc[index] * 20);
					vbuffer.put(zc[index] * 20);
					// random r,g,b
					cbuffer.put(.5f);
					cbuffer.put(.5f);
					cbuffer.put(.5f);
					nbuffer.put(xn[index]);
					nbuffer.put(yn[index]);
					nbuffer.put(zn[index]);
				}
			}

			vbuffer.rewind();
			cbuffer.rewind();
			nbuffer.rewind();

			gl2.glEnableClientState(GL2.GL_VERTEX_ARRAY);
			gl2.glVertexPointer(3, GL2.GL_FLOAT, 0, vbuffer);

			gl2.glEnableClientState(GL2.GL_COLOR_ARRAY);
			gl2.glColorPointer(3, GL2.GL_FLOAT, 0, cbuffer);

			gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY);
		    gl2.glNormalPointer(GL2.GL_FLOAT, 0, nbuffer);
			pg.endPGL();

			projMatrix = new float[16];
			mvMatrix = new float[16];
		}
		
		public void drawOpenGL() {
			parent.background(0);
			PGraphicsOpenGL pg = ((PGraphicsOpenGL) parent.g);
			PGL pgl = pg.beginPGL();
			GL2 gl2 = pgl.gl.getGL2();
			gl2.glViewport(0, 0,parent.width, parent.height);
			gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

			setLights(gl2);
			//gl2.glShadeModel(GL2.gl_flat);
			gl2.glShadeModel(GL2.GL_SMOOTH);
			float shade = 1;
			float material[] = { shade, shade, shade, 1.0f };
			gl2.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE,
					material, 0);
			

			boolean ison = true;
			/*if (ison) {
				gl2.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE);
			} else {
				gl2.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
			}*/

			gl2.glEnable(GLLightingFunc.GL_LIGHTING);
			gl2.glMatrixMode(GL2.GL_PROJECTION);
			projMatrix[0] = pg.projection.m00;
			projMatrix[1] = pg.projection.m10;
			projMatrix[2] = pg.projection.m20;
			projMatrix[3] = pg.projection.m30;

			projMatrix[4] = pg.projection.m01;
			projMatrix[5] = pg.projection.m11;
			projMatrix[6] = pg.projection.m21;
			projMatrix[7] = pg.projection.m31;

			projMatrix[8] = pg.projection.m02;
			projMatrix[9] = pg.projection.m12;
			projMatrix[10] = pg.projection.m22;
			projMatrix[11] = pg.projection.m32;

			projMatrix[12] = pg.projection.m03;
			projMatrix[13] = pg.projection.m13;
			projMatrix[14] = pg.projection.m23;
			projMatrix[15] = pg.projection.m33;

			gl2.glLoadMatrixf(projMatrix, 0);

			gl2.glMatrixMode(GL2.GL_MODELVIEW);
			mvMatrix[0] = pg.modelview.m00;
			mvMatrix[1] = pg.modelview.m10;
			mvMatrix[2] = pg.modelview.m20;
			mvMatrix[3] = pg.modelview.m30;

			mvMatrix[4] = pg.modelview.m01;
			mvMatrix[5] = pg.modelview.m11;
			mvMatrix[6] = pg.modelview.m21;
			mvMatrix[7] = pg.modelview.m31;

			mvMatrix[8] = pg.modelview.m02;
			mvMatrix[9] = pg.modelview.m12;
			mvMatrix[10] = pg.modelview.m22;
			mvMatrix[11] = pg.modelview.m32;

			mvMatrix[12] = pg.modelview.m03;
			mvMatrix[13] = pg.modelview.m13;
			mvMatrix[14] = pg.modelview.m23;
			mvMatrix[15] = pg.modelview.m33;
			
			gl2.glLoadMatrixf(mvMatrix, 0);
			gl2.glPushMatrix();
			gl2.glTranslatef(parent.width / 2, parent.height / 2, 0);
			gl2.glTranslatef(tx + txt, -(ty + tyt), 0);
			gl2.glScalef(sc + sct, sc + sct, sc + sct);
			gl2.glRotatef(-(rx + rxt), 1f, 0f, 0f);
			gl2.glRotatef(-(ry + ryt), 0f, 1f, 0f);
			gl2.glEnable(GL2.GL_RESCALE_NORMAL);
			gl2.glDrawArrays(GL2.GL_QUADS, 0, numPoints);
			gl2.glPopMatrix();
			pg.endPGL();
		}
		
		void setLights(GL2 gl2) {
			float light_ambient[] = new float[4], light_diffuse[] = new float[4], light_specular[] = new float[4], light_position[] = new float[4];

			gl2.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL2.GL_TRUE);
			light_ambient[0] = .1f;
			light_ambient[1] = .05f;
			light_ambient[2] = .05f;
			light_ambient[3] = 1;
			light_diffuse[0] = 1.2f;
			light_diffuse[1] = 1.1f;
			light_diffuse[2] = 1f;
			light_diffuse[3] = 1;
			light_specular[0] = .3f;
			light_specular[1] = .4f;
			light_specular[2] = .75f;
			light_specular[3] = 1;
			light_position[0] = -1.5f;
			light_position[1] = 1f;
			light_position[2] = -4f;
			light_position[3] = 0;

			gl2.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, light_ambient, 0);
			gl2.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, light_diffuse, 0);
			gl2.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, light_specular, 0);
			gl2.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, light_position, 0);
			gl2.glEnable(GL2.GL_LIGHT1);
			gl2.glEnable(GL2.GL_LIGHTING);

		}
		
		
		
		
		float mxi, myi;
		float rx, rxt, ry, ryt, rya, sc = 1, sct, mxt, myt, tx, txt, ty, tyt;
		float fovt, fovi;
		boolean rotation = false;
		
		public void mPressed(float mouseX, float mouseY) {
			mxi = mouseX;
			myi = mouseY;
		}
	
		public void mDragged(float mouseX, float mouseY, int mouseButton) {
			if (mouseButton == PApplet.RIGHT) {
				sct = (mouseX - mxi + myi - mouseY) * 2; // sct =
															// max(50-sc,sct);
			}
			if (mouseButton == PApplet.CENTER) {
				txt = (mouseX - mxi);
				tyt = (mouseY - myi);
			}
			if (mouseButton == PApplet.LEFT) {
				ryt = (mouseX - mxi);
				rxt = (mouseY - myi);
			}
		}
	
		public void mReleased() {
			rx = rx + rxt;
			rxt = 0;
			ry = ry + ryt;
			ryt = 0;
			tx = tx + txt;
			txt = 0;
			ty = ty + tyt;
			tyt = 0;
			sc = sc + sct;
			sct = 0; // sc = max(50,sc);
		}

		@Override
		public void mouseClicked(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mousePressed(MouseEvent m) {
			// TODO Auto-generated method stub
			mPressed(m.getX(),m.getY());
		}

		@Override
		public void mouseReleased(MouseEvent m) {
			// TODO Auto-generated method stub
			mReleased();
		}

		@Override
		public void mouseDragged(MouseEvent m) {
			// TODO Auto-generated method stub
			mDragged(m.getX(),m.getY(),parent.mouseButton);
		}

		@Override
		public void mouseMoved(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}
}
